package com.larry.isn.service;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

import org.apache.commons.collections.map.MultiKeyMap;

import com.pegatron.ers.util.StrUtil;
import com.pegatron.ers.vo.common.CommonDataModel;
import com.pegatron.ers.vo.common.CommonSQLStmt;

public class IsnCalcService {

	private final String SFIS = "sfis";

	private final String OBS = "obs";

	private final String CLIENT = "client";

	public static final String WEB_SERVICE = "WEBSERVICE";

	private CommonDataModel webServiceResult = new CommonDataModel();

	private Map<String, String> keyMap = new HashMap<String, String>();

	private MultiKeyMap dataMap = new MultiKeyMap();

	public void summarizedISN(List<CommonDataModel> list) throws Exception {
		this.prepareData(list);
		List<String> serialNrs = this.filterSerialNr();
		this.summarizedChart1Data(serialNrs);
		// chart 1
		this.exportDetailChart1(WEB_SERVICE, webServiceResult);
	}

	public CommonSQLStmt getDateRange() throws Exception {
		CommonSQLStmt pstmt = new CommonSQLStmt();
		StringBuffer buf = new StringBuffer();
		buf.append("	select");
		buf.append("		to_char(ct_date, 'yyyy/MM/dd') sfis_date");
		buf.append("	from");
		buf.append("		 ers_log_outbound");
		buf.append("	where");
		buf.append("		system='SFIS'");
		buf.append("	group by to_char(ct_date, 'yyyy/MM/dd')");
		buf.append("	order by to_char(ct_date, 'yyyy/MM/dd')");
		pstmt.setSql(buf.toString());
		return pstmt;
	}

	public CommonSQLStmt getSql(String date) throws Exception {
		CommonSQLStmt pstmt = new CommonSQLStmt();
		StringBuffer buf = new StringBuffer();
		buf.append("	select");
		buf.append("		a.log_key,");
		buf.append("		a.serial_nr,");
		buf.append("		a.req_no,");
		buf.append("		a.req_type,");
		buf.append("		a.data_got data_got,");
		buf.append("		a.status,");
		buf.append("		a.memo4,");
		buf.append("		b.spot,");
		buf.append("		b.ct_date,");
		buf.append("		to_char(b.ct_date, 'yyyy/MM/dd') sfis_date,");
		buf.append("		(b.ct_date - c.ct_date) * 3600 * 24 as sfis_cost,");
		buf.append("		(d.ct_date - e.ct_date) * 3600 * 24 as obs_cost,");
		buf.append("		(f.ct_date - g.ct_date) * 3600 * 24 as client_cost");
		buf.append("	from");
		buf.append("		ers_log_outbound a,");
		buf.append("		(select * from ers_log_spot where track_no=5) b,");
		buf.append("		(select * from ers_log_spot where track_no=4) c,");
		buf.append("		(select * from ers_log_spot where track_no=7) d,");
		buf.append("		(select * from ers_log_spot where track_no=2) e,");
		buf.append("		(select * from ers_log_spot where track_no=8) f,");
		buf.append("		(select * from ers_log_spot where track_no=1) g");
		buf.append("	where");
		buf.append("		1=1");
		if (!StrUtil.isEmpty(date)) {
			buf.append("	and to_char(a.ct_date, 'yyyy/MM/dd')='" + date + "'");
		}
		buf.append("		and a.req_type in ('WEBSERVICE')");
		buf.append("		and a.log_key=b.log_key(+)");
		buf.append("		and a.req_no=b.req_no(+)");
		buf.append("		and a.log_key = c.log_key(+)");
		buf.append("		and a.req_no = c.req_no(+)");
		buf.append("		and a.log_key = d.log_key(+)");
		buf.append("		and a.req_no = d.req_no(+)");
		buf.append("		and a.log_key = e.log_key(+)");
		buf.append("		and a.req_no = e.req_no(+)");
		buf.append("		and a.log_key = f.log_key(+)");
		buf.append("		and a.req_no = f.req_no(+)");
		buf.append("		and a.log_key = g.log_key(+)");
		buf.append("		and a.req_no = g.req_no(+)");
		pstmt.setSql(buf.toString());
		return pstmt;
	}

	private void prepareData(List<CommonDataModel> list) throws Exception {
		for (CommonDataModel data : list) {
			String serialNr = data.getString("serial_nr");
			String reqType = data.getString("req_type");
			dataMap.put(serialNr, reqType, data);
			keyMap.put(serialNr, serialNr);
		}
	}

	private List<String> filterSerialNr() throws Exception {
		List<String> serialNrs = new ArrayList<String>();
		for (String serialNr : keyMap.keySet()) {
			if (serialNr.equals("1194004800576")) {
				System.out.println("Why");
			}
			serialNrs.add(serialNr);
		}
		return serialNrs;
	}

	private void summarizedChart1Data(List<String> serialNrs) throws Exception {
		webServiceResult.put("sn", serialNrs.size());
		for (String serialNr : serialNrs) {
			summarizedChart1Data(serialNr, WEB_SERVICE, dataMap, webServiceResult);
		}
	}

	private void summarizedChart1Data(String serialNr, String reqType, MultiKeyMap dataMap, CommonDataModel result) throws Exception {
		CommonDataModel newData = (CommonDataModel) dataMap.get(serialNr, reqType);
		String status = newData.getString("status");
		String dataGot = newData.getString("data_got");
		if (!"S".equalsIgnoreCase(status)) {
			this.connectSum("no_success", SFIS, newData, result);
			return;
		}
		this.summarized("success", newData, result);
		this.calcTimeRange("success", SFIS, newData, result);
		if (!"Y".equals(dataGot)) {
			this.summarized("no_data", newData, result);
			return;
		}
		this.summarized("data_got", newData, result);
	}

	private void summarized(String resultType, CommonDataModel newData, CommonDataModel result) throws Exception {
		this.connectSum(resultType, SFIS, newData, result);
		this.calcExcuteTime(resultType, SFIS, newData, result);
		this.calcMaxExcuteTime(resultType, SFIS, newData, result);
		this.connectSum(resultType, OBS, newData, result);
		this.calcExcuteTime(resultType, OBS, newData, result);
		this.calcMaxExcuteTime(resultType, OBS, newData, result);
		this.connectSum(resultType, CLIENT, newData, result);
		this.calcExcuteTime(resultType, CLIENT, newData, result);
		this.calcMaxExcuteTime(resultType, CLIENT, newData, result);
	}

	private void connectSum(String resultType, String systemType, CommonDataModel newData, CommonDataModel result) throws Exception {
		if (this.isExisted(systemType + "_cost", newData)) {
			String connectKey = this.getSumKey(resultType, systemType);
			BigDecimal cacheConnectTimes = !this.isExisted(connectKey, result) ? new BigDecimal("0") : result.getBigDecimal(connectKey);
			cacheConnectTimes = cacheConnectTimes.add(new BigDecimal("1"));
			result.put(connectKey, cacheConnectTimes);
		}
	}

	private void calcExcuteTime(String resultType, String systemType, CommonDataModel newData, CommonDataModel result) throws Exception {
		String totalKey = this.getTotalKey(resultType, systemType);
		systemType = systemType + "_cost";
		BigDecimal totalExceuteTime = !this.isExisted(totalKey, result) ? new BigDecimal("0") : result.getBigDecimal(totalKey);
		result.put(totalKey, totalExceuteTime.add(newData.getBigDecimal(systemType)));
	}

	private void calcMaxExcuteTime(String resultType, String systemType, CommonDataModel newData, CommonDataModel result) throws Exception {
		String maxKey = this.getMaxKey(resultType, systemType);
		BigDecimal maxCost = result.getBigDecimal(maxKey);
		systemType = systemType + "_cost";
		BigDecimal currentCost = newData.getBigDecimal(systemType);
		maxCost = maxCost.compareTo(currentCost) >= 0 ? maxCost : currentCost;
		result.put(maxKey, maxCost);
	}

	@SuppressWarnings("unchecked")
	private void calcTimeRange(String resultType, String systemType, CommonDataModel newData, CommonDataModel result) throws Exception {
		TreeMap<BigDecimal, BigDecimal> timeRange = new TreeMap<BigDecimal, BigDecimal>();
		String timeRangeKey = this.getTimeRangeKey(resultType, systemType);
		if (this.isExisted(timeRangeKey, result)) {
			timeRange = (TreeMap<BigDecimal, BigDecimal>) result.get(timeRangeKey);
		}
		systemType = systemType + "_cost";
		BigDecimal excuteTime = newData.getBigDecimal(systemType).setScale(0, BigDecimal.ROUND_DOWN);
//		if (excuteTime.compareTo(new BigDecimal(10))>=0) {
//			excuteTime = new BigDecimal("10");
//		}
		BigDecimal cacheSizes = BigDecimal.ZERO;
		if (timeRange.get(excuteTime) != null) {
			cacheSizes = timeRange.get(excuteTime);
		}
		cacheSizes = cacheSizes.add(new BigDecimal("1"));
		timeRange.put(excuteTime, cacheSizes);
		result.put(timeRangeKey, timeRange);
	}

	private Boolean isExisted(String key, CommonDataModel data) throws Exception {
		if (data.get(key) == null || "-1".equals(data.get(key))) {
			return false;
		}
		return true;
	}

	@SuppressWarnings("unchecked")
	private void exportDetailChart1(String reqType, CommonDataModel result) throws Exception {
		Integer totalSn = (Integer) result.get("sn");
		System.out.println("total sn====>" + totalSn);

		this.printResult(totalSn, "success", SFIS, result);
		this.printResult(totalSn, "success", OBS, result);
		this.printResult(totalSn, "success", CLIENT, result);

		this.printResult(totalSn, "data_got", SFIS, result);
		this.printResult(totalSn, "data_got", OBS, result);
		this.printResult(totalSn, "data_got", CLIENT, result);

		this.printResult(totalSn, "no_data", SFIS, result);
		this.printResult(totalSn, "no_data", OBS, result);
		this.printResult(totalSn, "no_data", CLIENT, result);

		try {
			this.printResult(totalSn, "no_success", SFIS, result);
		} catch (Exception e) {
			// TODO: handle exception
		}
		
		
		TreeMap<BigDecimal, BigDecimal> timeRange = (TreeMap<BigDecimal, BigDecimal>) result.get(this.getTimeRangeKey("success", SFIS));
		for (BigDecimal excuteTime : timeRange.keySet()) {
			System.out.println("excute time====>"+excuteTime+"(" + timeRange.get(excuteTime) + ")");
		}
	}

	private void printResult(Integer totalSn, String resultType, String systemType, CommonDataModel result) throws Exception {
		String sumKey = this.getSumKey(resultType, systemType);
		BigDecimal numSum = !this.isExisted(sumKey, result) ? BigDecimal.ZERO : result.getBigDecimal(sumKey);
		System.out.println(resultType + " " + systemType + " sum====>" + numSum);
		String rate = numSum.divide(new BigDecimal(totalSn), 4, BigDecimal.ROUND_HALF_UP).multiply(new BigDecimal("100")).setScale(2, BigDecimal.ROUND_HALF_UP) + "%";
		System.out.println(resultType + " " + systemType + " rate====>" + rate);

		String totalExcuteKey = this.getTotalKey(resultType, systemType);
		BigDecimal totalCost = !this.isExisted(totalExcuteKey, result) ? BigDecimal.ZERO : result.getBigDecimal(totalExcuteKey);
		BigDecimal averageCost = BigDecimal.ZERO;
		if (!numSum.equals(new BigDecimal("0"))) {
			averageCost = totalCost.divide(numSum, 4, BigDecimal.ROUND_HALF_UP);
		}
		System.out.println("average " + resultType + " " + systemType + " excute time====>" + averageCost);
		String maxExcuteKey = this.getMaxKey(resultType, systemType);
		BigDecimal maxCost = !this.isExisted(maxExcuteKey, result) ? BigDecimal.ZERO : result.getBigDecimal(maxExcuteKey);
		System.out.println("max " + resultType + " " + systemType + " excute time====>" + maxCost);
	}

	private String getSumKey(String resultType, String systemType) {
		return resultType + "_" + systemType + "_sum";
	}

	private String getTotalKey(String resultType, String systemType) throws Exception {
		return "total_" + resultType + "_" + systemType + "_cost";
	}

	private String getMaxKey(String resultType, String systemType) throws Exception {
		return "max_" + resultType + "_" + systemType + "_cost";
	}
	
	private String getTimeRangeKey(String resultType, String systemType) throws Exception {
		return resultType + "_" + systemType + "_time_range";
	}
}
